package one.stand.service.impl;

import lombok.extern.slf4j.Slf4j;
import one.stand.advice.ResultEnum;
import one.stand.event.UpdateGoodsTypeEvent;
import one.stand.mapper.GoodstypeMapperExt;
import one.stand.model.GoodsType;
import one.stand.model.GoodstypeModel;
import one.stand.service.GoodsTypeService;
import one.stand.util.AssertUtil;
import one.stand.util.OneConstant;
import one.stand.util.OneListUtil;
import one.stand.util.SqlUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author cjr
 */
@Service
@Slf4j
public class GoodsTypeServiceImpl implements GoodsTypeService {
    @Autowired
    private GoodstypeMapperExt goodstypeMapperExt;
    @Autowired
    private ApplicationContext applicationContext;

    @Override
    @Transactional
    public Integer save(Integer companyId, String name, Integer parentId, Integer id, Integer isShow, String photo) {
        AssertUtil.nonNull(companyId, ResultEnum.NO_PARAM);
        AssertUtil.nonNull(name, ResultEnum.NO_PARAM);
        if (Objects.isNull(parentId)) {
            parentId = PARENT_ID;
        }
        name = name.trim();

        GoodsType model = new GoodsType();
        model.setGoodstypeId(id);
        model.setCompanyId(companyId);
        model.setName(name);
        model.setParentId(parentId);
        model.setIsShow(isShow);
        model.setPhoto(photo);
        if (isParent(parentId)) {
            model.setGroupName(name);
        } else {
            GoodsType parentType = goodstypeMapperExt.selectByPrimaryKey(parentId);
            AssertUtil.nonNull(parentType, ResultEnum.NO_PARAM);
            AssertUtil.isTrue(isParent(parentType.getParentId()), ResultEnum.NO_PARAM);
            model.setGroupName(parentType.getName() + SPLIT + name);
        }

        // groupName 唯一性校验
        GoodsType groupNameCheck = goodstypeMapperExt.selectByGroupName(companyId, model.getGroupName());

        int r;
        if (Objects.nonNull(id)) {
            // 校验
            AssertUtil.isTrue(Objects.isNull(groupNameCheck) || id.equals(groupNameCheck.getGoodstypeId()), "分类名称重复");
            List<GoodsType> childTypes = goodstypeMapperExt.selectListByParent(id, companyId, false);
            final boolean hasChild = OneListUtil.isNotEmpty(childTypes);
            if (hasChild) {
                AssertUtil.isTrue(isParent(parentId), "当前类下存在子类，不能修改为子类");
            }

            // update
            r = goodstypeMapperExt.updateByPrimaryKeySelective(model);

            // update group name of children type
            if (isParent(parentId) && hasChild) {
                goodstypeMapperExt.updateGroupName(model.getGoodstypeId(), model.getName());
            }
        } else {
            AssertUtil.isNull(groupNameCheck, "分类名称重复");

            model.setSort(goodstypeMapperExt.getGoodsTypeSortMax(model.getCompanyId()) + 1);
            r = goodstypeMapperExt.insertSelective(model);
        }
        AssertUtil.isTrue(r > 0, ResultEnum.FAIL);

        applicationContext.publishEvent(new UpdateGoodsTypeEvent(companyId));

        return model.getGoodstypeId();
    }

    @Override
    @Transactional
    public Integer saveCopy(Integer companyId, Integer goodstypeId) {
        GoodsType goodsType = goodstypeMapperExt.selectByPrimaryKey(goodstypeId);
        AssertUtil.nonNull(goodsType, ResultEnum.FAIL);
        AssertUtil.isFalse(isParent(goodsType.getParentId()), ResultEnum.FAIL);

        GoodsType companyGoodsType = goodstypeMapperExt.selectByGroupName(companyId, goodsType.getGroupName());
        if (Objects.nonNull(companyGoodsType)) {
            return companyGoodsType.getGoodstypeId();
        }

        GoodsType goodsTypeParent = goodstypeMapperExt.selectByPrimaryKey(goodsType.getParentId());
        AssertUtil.nonNull(goodsType, ResultEnum.FAIL);
        Integer parentId;
        GoodsType companyGoodsTypeParent = goodstypeMapperExt.selectByGroupName(companyId, goodsType.getGroupName());
        if (Objects.nonNull(companyGoodsTypeParent)) {
            parentId = companyGoodsTypeParent.getGoodstypeId();
        } else {
            parentId = save(companyId, goodsTypeParent.getName(), null, null, 0, null);
        }

        return save(companyId, goodsType.getName(), parentId, null, 0, null);
    }

    @Override
    @Transactional
    public Integer saveImport(Integer companyId, String typeGroupName) {
        String[] types = typeGroupName.split(SPLIT);
        AssertUtil.nonNull(types, "分类不能为空");
        AssertUtil.isTrue(types.length == 2, "分类格式不合法");
        AssertUtil.isTrue(StringUtils.isNoneBlank(types[0], types[1]), "分类不能为空");

        GoodsType goodsType = goodstypeMapperExt.selectByGroupName(companyId, typeGroupName);
        if (Objects.nonNull(goodsType)) {
            return goodsType.getGoodstypeId();
        }

        String typeParent = types[0];
        goodsType = goodstypeMapperExt.selectByGroupName(companyId, typeParent);
        Integer sort = goodstypeMapperExt.getGoodsTypeSortMax(companyId) + 1;
        if (Objects.isNull(goodsType)) {
            goodsType = new GoodsType();
            goodsType.setCompanyId(companyId);
            goodsType.setName(typeParent);
            goodsType.setParentId(0);//0 父类
            goodsType.setSort(sort);
            goodsType.setGroupName(typeParent);
            goodstypeMapperExt.insertSelective(goodsType);
            sort = sort + 1;
        }

        Integer typeIdChild = goodsType.getGoodstypeId();

        goodsType = new GoodsType();
        goodsType.setCompanyId(companyId);
        goodsType.setName(types[1]);
        goodsType.setParentId(typeIdChild);
        goodsType.setSort(sort);
        goodsType.setGroupName(typeGroupName);
        goodstypeMapperExt.insertSelective(goodsType);

        applicationContext.publishEvent(new UpdateGoodsTypeEvent(companyId));

        return goodsType.getGoodstypeId();
    }

    @Override
    @Transactional
    public void remove(Integer id) {
        GoodsType goodstypeModel = goodstypeMapperExt.selectByPrimaryKey(id);
        goodstypeMapperExt.delGoodsType(id);
        if (isParent(goodstypeModel.getParentId())) {
            List<GoodsType> childList = goodstypeMapperExt.selectListByParent(id, null, false);
            if (OneListUtil.isNotEmpty(childList)) {
                List<Integer> ids = childList.stream().map(GoodsType::getGoodstypeId).collect(Collectors.toList());
                String idsStr = SqlUtil.in(ids);
                goodstypeMapperExt.updateDelByIds(idsStr);
            }
        }

        applicationContext.publishEvent(new UpdateGoodsTypeEvent(goodstypeModel.getCompanyId()));
    }

    @Override
    public void deleteByIds(List<Integer> typeIds) {
        goodstypeMapperExt.updateDelByIds(SqlUtil.in(typeIds));

        GoodsType goodstypeModel = goodstypeMapperExt.selectByPrimaryKey(typeIds.get(0));
        applicationContext.publishEvent(new UpdateGoodsTypeEvent(goodstypeModel.getCompanyId()));
    }

    @Override
    @Transactional
    public void updateSort(Integer id, Integer type, Integer companyId) {
        log.info("商品类型移动：{} {} {}", id, type, companyId);
        AssertUtil.nonNull(id, ResultEnum.NO_PARAM);
        AssertUtil.nonNull(type, ResultEnum.NO_PARAM);
        AssertUtil.nonNull(companyId, ResultEnum.NO_PARAM);

        // 查询被上移的商品分类id
        GoodstypeModel model = new GoodstypeModel();
        model.setGoodstypeId(id);
        model.setType(type);
        model.setCompanyId(companyId);
        GoodsType goodsTypeModel = goodstypeMapperExt.getThanGoodsTypeId(id, type);
        AssertUtil.nonNull(goodsTypeModel, ResultEnum.PARAM_CHECK, OneConstant.ONE.equals(type) ? "到顶了，无法上移！" : "到底了，无法下移！");

        // 修改分类
        GoodsType goodsType = goodstypeMapperExt.selectByPrimaryKey(id);
        Integer lastSort = goodsType.getSort();
        goodsType = new GoodsType();
        goodsType.setGoodstypeId(id);
        goodsType.setSort(goodsTypeModel.getSort());
        int r = goodstypeMapperExt.updateByPrimaryKeySelective(goodsType);
        if (r > 0) {
            goodsType = new GoodsType();
            goodsType.setGoodstypeId(goodsTypeModel.getGoodstypeId());
            goodsType.setSort(lastSort);
            goodstypeMapperExt.updateByPrimaryKeySelective(goodsType);
        }

        applicationContext.publishEvent(new UpdateGoodsTypeEvent(companyId));
    }

    @Override
    public void updateGoodsTypeIsShow(Integer goodstypeId, Integer isShow) {
        GoodsType type = new GoodsType();
        type.setGoodstypeId(goodstypeId);
        type.setIsShow(isShow);
        goodstypeMapperExt.updateByPrimaryKeySelective(type);
    }

    @Override
    public GoodsType get(Integer id) {
        return goodstypeMapperExt.selectByPrimaryKey(id);
    }

    @Override
    public List<GoodsType> getParent(Integer companyId) {
        if (companyId == null) {
            return null;
        }
        return goodstypeMapperExt.selectGoodsTypeParent(companyId);
    }

    @Override
    public List<GoodsType> getChild(Integer goodstypeId, Integer companyId) {
        if (Objects.isNull(goodstypeId)) {
            AssertUtil.nonNull(companyId, ResultEnum.NO_PARAM);
            goodstypeId = PARENT_ID;
        }
        return goodstypeMapperExt.selectChilds(goodstypeId, companyId);
    }

    @Override
    public List<GoodsType> getAllChild(Integer companyId) {
        return goodstypeMapperExt.selectChildList(companyId);
    }

    @Override
    public List<Integer> getChildrenForCheck(Integer id) {
        GoodsType goodstypeModel = goodstypeMapperExt.selectByPrimaryKey(id);
        if (isParent(goodstypeModel.getParentId())) {
            List<GoodsType> childList = goodstypeMapperExt.selectChilds(id, null);
            return childList.stream().map(GoodsType::getGoodstypeId).collect(Collectors.toList());
        }
        return null;
    }

    private boolean isParent(Integer parentId) {
        return Objects.nonNull(parentId) && PARENT_ID == parentId;
    }
}
